package cn.geminis.lowcode.compiler.code;

import cn.geminis.lowcode.compiler.util.JdkTreeMakerUtils;
import cn.geminis.lowcode.utils.Flags;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.VariableTree;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import javax.lang.model.element.VariableElement;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;

/**
 * @author puddi
 */
@RequiredArgsConstructor
public class LcVariable extends AbstractStatement<VariableTree> {

    private final LcModifier modifiers;
    @Getter
    private final String type;
    @Getter
    private final String name;
    private final ExpressionTree init;
    private final boolean declareUsingVar;

    public LcVariable(VariableElement element) {
        super(element);
        var tree = this.getJdkTree();
        this.modifiers = null;// new LcModifier(this.getJdkTree().getModifiers());
        this.type = tree.getType().toString();
        this.name = tree.getName().toString();
        this.init = tree.getInitializer();
        this.declareUsingVar = false;
    }

    public LcVariable(VariableTree tree) {
        super(tree);
        this.modifiers = null;
        this.type = tree.getType().toString();
        this.name = tree.getName().toString();
        this.init = tree.getInitializer();
        this.declareUsingVar = false;
    }

    public LcVariable(LcModifier modifiers, String type, String name) {
        this(modifiers, type, name, null, false);
    }

    public LcVariable(String type, String name) {
        this(new LcModifier(Flags.PARAMETER), type, name, null, false);
    }

    public LcVariable(String type, String name, ExpressionTree init) {
        this(new LcModifier(Flags.PARAMETER), type, name, init, true);
    }

    @Override
    protected VariableTree createJdkTree() {
        return JdkTreeMakerUtils.variableDef(
                this.modifiers.getJdkTree(),
                type,
                name,
                init,
                declareUsingVar
        );
    }

    @Override
    protected VariableElement createJdkElement() {
        return null;
    }

    public <T extends Annotation> List<T> getAnnotation(Class<T> clazz) {
        var element = this.getJdkElement();
        if (element == null) {
            var a = this.getJdkTree().getModifiers().getAnnotations().stream()
                    .filter(annotation -> annotation.getAnnotationType().toString().equals(clazz.getName()))
                    .toList();
            return List.of();
        } else {
            return Arrays.stream(element.getAnnotationsByType(clazz)).toList();
        }
    }

    public boolean existAnnotation(String annotationType) {
        var element = this.getJdkElement();
        if (element == null) {
            return this.getJdkTree().getModifiers().getAnnotations().stream()
                    .anyMatch(annotation -> annotation.getAnnotationType().toString().equals(annotationType));
        } else {
            return element.getAnnotationMirrors().stream().anyMatch(
                    annotation -> annotation.getAnnotationType().toString().equals(annotationType)
            );
        }
    }
}
